export type Interceptor = (input: RequestInfo, init: RequestInit, response?: any) => Promise<void> | void;

const toQueryString = (params: Record<string, any>): string => {
  const query = Object.entries(params)
  .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
  .join('&');
  return query ? `?${query}` : '';
};
const utils = {
  replacePathLastSlash({
                         value = '',
                         includeSlash = true,
                       }: { value?: string, includeSlash?: boolean }) {
    value = value.replace(/^([^|]+)(\/)$/g, '$1');
    return value + (includeSlash ? '/' : '');
  },
  addLashSlash(value: string = '') {
    return utils.replacePathLastSlash({ value, includeSlash: true });
  },
  replacePathFirstSlash({
                          value = '',
                          includeSlash = true,
                        }: { value?: string, includeSlash?: boolean }) {
    value = value.replace(/^(\/)([^|]+)$/g, '$2');
    return (includeSlash ? '/' : '') + value;
  },
  removeFirstSlash(value: string = '') {
    return utils.replacePathFirstSlash({ value, includeSlash: false });
  },
};

export interface HttpClientProxy {

  request(method: string, endpoint: string, body?: any, headers?: Record<string, string>): Promise<any>;

  get(endpoint: string, headers?: Record<string, string>): Promise<any>;

  delete(endpoint: string, body?: any, headers?: Record<string, string>): Promise<any>;

  post(endpoint: string, body: any, headers?: Record<string, string>): Promise<any>;

  put(endpoint: string, body: any, headers?: Record<string, string>): Promise<any>;
}

export class HttpClient {
  private readonly baseUrl: string;
  private requestInterceptors: Interceptor[] = [];
  private responseInterceptors: Interceptor[] = [];
  private defaultHeaders: Record<string, string> = {};
  private httpClientProxy: HttpClientProxy | undefined;

  constructor(baseUrl: string) {
    this.baseUrl = baseUrl;
  }

  // 添加拦截器
  addInterceptor(interceptor: Interceptor, type: 'request' | 'response' = 'request') {
    type === 'request' ? this.requestInterceptors.push(interceptor) : this.responseInterceptors.push(interceptor);
  }

  // 设置默认的 headers
  setDefaultHeaders(headers: Record<string, string>) {
    this.defaultHeaders = headers;
  }

  addHeaders(headers: Record<string, string>) {
    this.defaultHeaders = { ...this.defaultHeaders, ...headers };
  }

  setHttpClientProxy(httpClientProxy: HttpClientProxy) {
    this.httpClientProxy = httpClientProxy;
  }

  // 核心的 fetch 方法
  private async request(method: string, endpoint: string, data?: any, header?: Record<string, string>): Promise<any> {
    if (this.httpClientProxy) {
      return this.httpClientProxy.request(method, endpoint, data, header);
    }
    const url = `${utils.addLashSlash(this.baseUrl)}${utils.removeFirstSlash(endpoint)}`;
    const isFormData = data instanceof FormData;
    const headers = {
      ...this.defaultHeaders,
      ...header || ({}),
    };
    let body = data;
    if (!isFormData) {
      headers['Content-Type'] = 'application/json;charset=UTF-8';
      body = data ? JSON.stringify(data) : data;
    }
    const init: RequestInit = { method, headers, body };
    // 执行拦截器
    for (const interceptor of this.requestInterceptors) {
      await interceptor(url, init);
    }

    const response = await fetch(url, init);
    const json = (await response.json());
    const resp = {
      ...response, json: () => json,
    };
    for (const interceptor of this.responseInterceptors) {
      await interceptor(url, init, resp);
    }
    if (!response.ok) {
      throw resp;
    }
    return json;
  }

  // GET 请求 (支持参数传递)
  get(endpoint: string, params?: Record<string, any>, headers?: Record<string, string>) {
    const queryString = params ? toQueryString(params) : '';
    if (this.httpClientProxy) {
      return this.httpClientProxy.get(endpoint, headers);
    }
    return this.request('GET', `${endpoint}${queryString}`, null, headers);
  }

  // POST 请求
  post(endpoint: string, body: any, headers?: Record<string, string>) {
    if (this.httpClientProxy) {
      return this.httpClientProxy.post(endpoint, body, headers);
    }
    return this.request('POST', endpoint, body, headers);
  }

  // PUT 请求
  put(endpoint: string, body: any, headers?: Record<string, string>) {
    if (this.httpClientProxy) {
      return this.httpClientProxy.put(endpoint, body, headers);
    }
    return this.request('PUT', endpoint, body, headers);
  }

  // DELETE 请求
  delete(endpoint: string, body?: any, headers?: Record<string, string>) {
    if (this.httpClientProxy) {
      return this.httpClientProxy.delete(endpoint, body, headers);
    }
    return this.request('DELETE', endpoint, body, headers);
  }
}
